-module(light).
-export([new/0, new/3]).
-export([get_color/1, set_color/2]).
-export([get_position/1, set_position/2]).
-export([get_intensity/1, set_intensity/2]).
-export([check/2, hittest/2]).

-record(light, {
        position={},
        color=color:white(),
        intensity=1
       }).

new() -> #light{}.
new(Position, Color, Intensity) ->
    #light{position=Position, color=Color, intensity=Intensity}.

get_color(Light) -> Light#light.color.
set_color(Color, Light) -> Light#light{color=Color}.

get_position(Light) -> Light#light.position.
set_position(Position, Light) -> Light#light{position=Position}.

get_intensity(Light) -> Light#light.intensity.
set_intensity(Intensity, Light) -> Light#light{intensity=Intensity}.


hittest(Ray, Scene) ->
    Lights = scene:get_lights(Scene),
    case hittest(Ray, Lights, {1000000000000000000000000000, undefined}) of
        {_, undefined} -> false;
        Hit -> Hit
    end.

hittest(_Ray, [], Hit) -> Hit;
hittest(Ray, [Light|Tail], Hit) ->
    {RPos, RDir} = ray:split(Ray),
    LPos = light:get_position(Light),
    Dst = vector:dif(RPos, LPos),
    B = vector:dprod(Dst, RDir),
    C = vector:dprod(Dst,Dst) - 10,
    D = B*B - C,
    case D > 0 of
        true ->
            {Dist, _L} = Hit,
            CDist = vector:distance(RPos, LPos),
            case CDist < Dist of
                true -> hittest(Ray, Tail, {CDist, Light});
                false -> hittest(Ray, Tail, Hit)
            end;
        false -> hittest(Ray, Tail, Hit)
    end.


check(Pos, Scene) ->
    Lights = scene:get_lights(Scene),
    test(Pos, Lights, Scene, []).

test(_Pos, [], _Scene, Hits) -> Hits;
test(Pos, [Light|Tail], Scene, Hits) ->
    LPos = light:get_position(Light),
    Dir = vector:normalize(vector:dif(LPos, Pos)),

    TestRay = ray:new(Pos, Dir),
    case ray:hittest(TestRay, Scene) of
        false -> test(Pos, Tail, Scene, [Light|Hits]);
        {D, _Face, _UV} ->
            case D < 0.000001 of
                true -> test(Pos, Tail, Scene, [Light|Hits]);
                false -> test(Pos, Tail, Scene, Hits)
            end
    end.

